package network

import (
    "../log"
    "errors"
    "fmt"
    "net"
    //"runtime"
    //"sync/atomic"
)

//////////////////////////////////////////////////////////////////////////
//Connector
//////////////////////////////////////////////////////////////////////////
type Connector interface {
}

//////////////////////////////////////////////////////////////////////////
//TcpConnector
//////////////////////////////////////////////////////////////////////////
type TcpConnector struct {
    Socket

    evp *EventProcessor

    host string
    port int

    handler map[int32]func(pack *Packet) int

    //chan_join chan int
    /*
    	event_callback_ConnectionLose       func(err error)
    	event_callback_UnknowPacketReceived func(pack *Packet)

    	//event code define
    	EVCODE_CONNECT_LOSE            int64
    	EVCODE_CONNECT_PACKET_RECEIVED int64
    */
}

func NewConnector(name string, evp *EventProcessor, rcv_buf int, snd_buf int, sndchan int, log log.Log) *TcpConnector {
    obj := new(TcpConnector)
    obj.Constructor(name, evp, rcv_buf, snd_buf, sndchan, log)
    return obj
}

func (self *TcpConnector) Constructor(name string, evp *EventProcessor, rcv_buf int, snd_buf int, sndchan int, log log.Log) {
    self.evp = evp
    self.log = log
    if self.evp == nil {
        self.evp = NewEventProcessor()
    }

    self.handler = make(map[int32]func(pack *Packet) int)
    //self.chan_join = make(chan int, 10)
    /*
    	self.event_callback_ConnectionLose = func(err error) {
    		self.Warning("ConnectionLose: (%v +> %v) err:%v", self.GetLocalAddr(), self.GetRemoteAddr(), err)
    	}

    	self.event_callback_UnknowPacketReceived = func(pack *Packet) {

    	}*/

    return
}

func (self *TcpConnector) AddEventListener(proc func(args ...interface{})) int64 {
    return self.evp.AddEventListener(proc)
}

func (self *TcpConnector) DispatchEvent(ev_code int64, args ...interface{}) {
    self.evp.DispatchEvent(ev_code, args...)
}

func (self *TcpConnector) AddProtocol(des int32, proc func(pack *Packet) int) bool {
    ret := false
    if !self.is_running() {
        self.handler[des] = proc
        ret = true
    }

    return ret
}

/*
func (self *TcpConnector) SetEventCallback_ConnectionLose(callback func(err error)) {
	self.event_callback_ConnectionLose = callback
}

func (self *TcpConnector) SetEventCallback_UnknowPacketReceived(callback func(pack *Packet)) {
	self.event_callback_UnknowPacketReceived = callback
}*/

func (self *TcpConnector) Connect(ip string, port int) error {
    if self.is_running() {
        return errors.New(fmt.Sprintf("already connect (%v:%v)", self.host, self.port))
    }

    self.host = ip
    self.port = port
    str_connect := fmt.Sprintf("%v:%v", ip, port)
    fd, err := net.Dial("tcp", str_connect)

    if err != nil {
        return err
    }
    self.fd = fd.(*net.TCPConn)

    self.set_state_running()
    self.Success("ConnectionMade: (%v -> %v) err:%v", self.GetLocalAddr(), self.GetRemoteAddr(), err)

    //event thread
    self.EVCODE_CONNECT_LOSE = self.AddEventListener(func(args ...interface{}) {
        err := args[0].(error)
        self.event_callback_exception_happen()
        self.event_callback_ConnectionLose(err)
    })
    self.EVCODE_CONNECT_PACKET_RECEIVED = self.AddEventListener(func(args ...interface{}) {
        pack := args[0].(*Packet)
        self.event_callback_packet_received(pack)
    })

    return nil
}

func (self *TcpConnector) Join() {

    if self.is_running() {
        _ = <-self.chan_join //chan_recv
        //var sent_index int
        //for sent_index = 0; sent_index < self.send_chan_num; sent_index++ {
        _ = <-self.chan_join //chan_sent
        //}
    }

    //self.set_state_stopped()
}

/*
func (self *TcpConnector) Error(format string, args ...interface{}) {
	self.log.Error(self.name, format, args...)
}

func (self *TcpConnector) Warning(format string, args ...interface{}) {
	self.log.Warning(self.name, format, args...)
}

func (self *TcpConnector) Success(format string, args ...interface{}) {
	self.log.Success(self.name, format, args...)
}

func (self *TcpConnector) Debug(format string, args ...interface{}) {
	self.log.Debug(self.name, format, args...)
}

func (self *TcpConnector) Stack(format string, args ...interface{}) {
	self.log.Stack(self.name, format, args...)
}

func (self *TcpConnector) Temp(format string, args ...interface{}) {
	self.log.Temp(self.name, format, args...)
}

func (self *TcpConnector) dispatch_event_packet_received(pack *Packet) {
	self.DispatchEvent(self.EVCODE_CONNECT_PACKET_RECEIVED, pack)
}

func (self *TcpConnector) event_callback_packet_received(pack *Packet) {

	proc_func := self.handler[(int32)(pack.Des)]
	if proc_func != nil && pack != nil {
		proc_func(pack)
	} else {
		self.event_callback_UnknowPacketReceived(pack)
	}

}

func (self *TcpConnector) dispatch_event_exception_close(err error) {
	self.DispatchEvent(self.EVCODE_CONNECT_LOSE, err)
}

func (self *TcpConnector) event_callback_exception_happen() {
	self.set_state_stopped()
	self.chan_sent <- nil //sent thread
	self.fd.Close()
}

func (self *TcpConnector) is_running() bool {
	return atomic.LoadInt64(&self.running) == 1
}

func (self *TcpConnector) set_state_running() {
	atomic.CompareAndSwapInt64(&self.running, 0, 1)
}

func (self *TcpConnector) set_state_stopped() {
	atomic.CompareAndSwapInt64(&self.running, 1, 0)
}
*/
